﻿// -----------------------------------------------------------------------
// <copyright file="UserDto.cs" company="JSC Centido">
//  Copyright (c) JSC Centido. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

using System;
using System.Globalization;
using System.Xml;
using System.Xml.Schema;

namespace Centido.Core.Dto
{
    /// <summary>
    ///   A data transfer object for a registered user.
    /// </summary>
    public class UserDto : DataTransferObject
    {
        /// <summary>
        ///   The name of the xml tag that is used to store this object.
        /// </summary>
        public const string XmlTag = "user";

        /// <summary>
        ///   The current xml schema version.
        /// </summary>
        public const string CurrentXmlSchemaVersion = "1";

        /// <summary>
        ///   The name of the xml attribute to store the user name.
        /// </summary>
        public const string NameAttribute = "name";

        /// <summary>
        ///   The name of the xml attribute to store the user display name
        /// </summary>
        public const string DisplayNameAttribute = "displayName";

        /// <summary>
        ///   The name of the xml attribute to store the user ability to change the schema.
        /// </summary>
        public const string CanChangeSchemaAttribute = "changeSchema";

        /// <summary>
        ///   The name of the xml attribute to store the user ability to change security settings.
        /// </summary>
        public const string CanChangeSecurityAttribute = "changeSecurity";

        /// <summary>
        ///   The name of the xml attribute to store the user ability to logon.
        /// </summary>
        public const string CanLogonAttribute = "logon";


        /// <summary>
        ///   Gets or sets the user name.
        /// </summary>
        public string Name { get; set; }


        /// <summary>
        ///   Gets or sets the user display name.
        /// </summary>
        public string DisplayName { get; set; }


        /// <summary>
        ///   Gets or sets the user ability to logon.
        /// </summary>
        public bool? CanLogon { get; set; }


        /// <summary>
        ///   Gets or sets the user ability to change the schema.
        /// </summary>
        public bool? CanChangeSchema { get; set; }


        /// <summary>
        ///   Gets or sets the user ability to change security settings.
        /// </summary>
        public bool? CanChangeSecurity { get; set; }


        /// <summary>
        ///   This method is reserved and should not be used. When implementing the IXmlSerializable interface, you should return null (Nothing in Visual Basic) from this method, and instead, if specifying a custom schema is required, apply the <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> to the class.
        /// </summary>
        /// <returns>
        ///   An <see cref="T:System.Xml.Schema.XmlSchema"/> that describes the XML representation of the object that is produced by the <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/> method and consumed by the <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/> method.
        /// </returns>
        public override XmlSchema GetSchema()
        {
            return null;
        }


        /// <summary>
        ///   Generates an object from its XML representation.
        /// </summary>
        /// <param name="reader">
        ///   The <see cref="T:System.Xml.XmlReader"/> stream from which the object is deserialized. 
        /// </param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        public override void ReadXml(XmlReader reader)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");

            if (reader == null)
                throw new ArgumentNullException("reader");

            reader.MoveToContent();

            // Reading the xml schema version
            var xmlSchemaVersion = ReadStringAttribute(reader, XmlSchemaVersionTag, isRequired: false);

            // If the xml schema version is not defined
            if (string.IsNullOrEmpty(xmlSchemaVersion)
                // or if it is the current xml schema version
                || xmlSchemaVersion == CurrentXmlSchemaVersion)
            {
                // Reading the user name
                Name = ReadStringAttribute(reader, NameAttribute);

                // Reading the user display name
                DisplayName = ReadStringAttribute(reader, DisplayNameAttribute, isRequired: false);

                // Reading the user logon ability
                CanLogon = ReadBoolAttribute(reader, CanLogonAttribute, isRequired: false);

                // Reading the user ability to change the schema
                CanChangeSchema = ReadBoolAttribute(reader, CanChangeSchemaAttribute, isRequired: false);

                // Reading the user ability to change security settings
                CanChangeSecurity = ReadBoolAttribute(reader, CanChangeSecurityAttribute, isRequired: false);

                var isEmptyElement = reader.IsEmptyElement;

                reader.ReadStartElement();

                if (!isEmptyElement)
                    reader.ReadEndElement();
            }
            else
                throw new ArgumentException(string.Format(
                    "The specified xml schema version is not supported (node = {0}, version = {1}).",
                    reader.Name,
                    xmlSchemaVersion));
        }


        /// <summary>
        ///   Converts an object into its XML representation.
        /// </summary>
        /// <param name="writer">
        ///   The <see cref="T:System.Xml.XmlWriter"/> stream to which the object is serialized. 
        /// </param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="writer"/> is null.</exception>
        public override void WriteXml(XmlWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");

            if (writer == null)
                throw new ArgumentNullException("writer");

            writer.WriteStartElement(XmlTag);

            // The xml schema version
            writer.WriteAttributeString(XmlSchemaVersionTag, CurrentXmlSchemaVersion);

            // The user name
            if (!string.IsNullOrEmpty(Name))
                writer.WriteAttributeString(NameAttribute, Name);

            // The user display name
            if (!string.IsNullOrEmpty(DisplayName))
                writer.WriteAttributeString(DisplayNameAttribute, DisplayName);

            // The user logon ability
            if (CanLogon.HasValue)
                writer.WriteAttributeString(CanLogonAttribute, 
                    CanLogon.Value.ToString(CultureInfo.InvariantCulture));

            // The user ability to change the schema
            if (CanChangeSchema.HasValue)
                writer.WriteAttributeString(CanChangeSchemaAttribute,
                    CanChangeSchema.Value.ToString(CultureInfo.InvariantCulture));

            // The user ability to change security settings
            if (CanChangeSecurity.HasValue)
                writer.WriteAttributeString(CanChangeSecurityAttribute,
                    CanChangeSecurity.Value.ToString(CultureInfo.InvariantCulture));

            writer.WriteEndElement();
        }


        /// <summary>
        ///   Copies the properties of the data transfer object to the
        /// specified user.
        /// </summary>
        /// <param name="user">The role.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="user"/> is null.</exception>
        public void CopyTo(User user)
        {
            if (user == null)
                throw new ArgumentNullException("user");

            // The user display name
            if (DisplayName != user.DisplayName)
                user.DisplayName = DisplayName;

            // The user logon ability
            if (CanLogon.HasValue && CanLogon != user.CanLogon)
                user.CanLogon = CanLogon.Value;

            // The user ability to change the schema
            if (CanChangeSchema.HasValue && CanChangeSchema != user.CanChangeSchema)
                user.CanChangeSchema = CanChangeSchema.Value;

            // The user ability to change security settings
            if (CanChangeSecurity.HasValue && CanChangeSecurity != user.CanChangeSecurity)
                user.CanChangeSecurity = CanChangeSecurity.Value;
        }


        /// <summary>
        ///   Creates a data transfer object for the specified user.
        /// </summary>
        /// <param name="user">The specified user.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="user"/> is null.</exception>
        /// <returns>Returns the data transfer object for the specified user.</returns>
        public static UserDto CreateFrom(User user)
        {
            if (user == null)
                throw new ArgumentNullException("user");

            var userDto = new UserDto
            {
                Name = user.Name,
                DisplayName = user.DisplayName,
                CanLogon = user.CanLogon,
                CanChangeSchema = user.CanChangeSchema,
                CanChangeSecurity = user.CanChangeSecurity
            };

            return userDto;
        }
    }
}
